package 单向链表;

import java.util.Iterator;
import java.util.function.Consumer;

// 单向链表
public class Test implements Iterable<Integer> {
    private Node head = null; // 头指针

    // 节点类
    public static class Node {
        int value;
        Node next;

        // 构造器: 方便
        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }


    // 从头增加节点
    public void addFirst(int value) {
        head = new Node(value, head);
    }

    // 从尾部增加节点
    public void addLast(int value) {
        // 先找到尾节点(封装成方法)
        Node last = findLast();
        if (last == null) {
            addLast(value);
            return;
        }
        last.next = new Node(value, null);
    }

    // 找尾节点
    private Node findLast() {
        if (head == null) {
            return null;
        }
        Node p;
        for (p = head; p.next !=null; p = p.next) {

        }
        return p;
    }


    // 遍历1: while循环
//    public void loop1() {
//        Node p = head;
//        while (p != null) {
//            System.out.println(p.value);
//            p = p.next;
//        }
//    }
//    这是平常方法, 这样我们就只能打印数据据, 如果想该功能就只能改代码, 所以有一种方法, 让调用者自己提供方法流程(这里可以先当公式记)
    public void loop1(Consumer<Integer> consumer) {
        Node p = head;
        while (p != null) {
            consumer.accept(p.value);
            p = p.next;
        }
    }

    // 遍历2: for循环
    public void loop2(Consumer<Integer> consumer) {

        for (Node p = head; p != null; p = p.next) {
            consumer.accept(p.value);
        }
    }

    // 遍历3: 迭代器遍历
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            Node p = head;

            @Override
            public boolean hasNext() { // 是否有下一个元素
                return p != null;
            }

            @Override
            public Integer next() { // 返回当前元素的值, 并指向下一个元素
                int v = p.value;
                p = p.next;
                return v;
            }
        };
    }





    // 根据给定的索引位置找到该节点
    public Node findNode(int index) {
        int i = 0;
        for (Node p = head; p != null; i++, p = p.next) {
            if (i == index) {
                return p;
            }
        }
        return null; //没找到
    }
    // 根据给定的索引位置找到该节点的值
    public int get(int index) {
        Node node = findNode(index);
        if (node == null) {
            try {
                throw new IllegalAccessException(String.format("index [%d] 不合法%n", index));
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return node.value;
    }
    // 根据索引插入
    public void insert(int index, int value) {
        Node pre = findNode(index - 1);// 找到上一个节点
        if (index == 0) {
            addFirst(value);
            return;
        }
        if (pre == null) {
            System.out.println("索引异常~~~");
            return;
        }
        pre.next = new Node(value, pre.next);
    }






    // 删除首节点
    public void removeFirst() {
        if (head == null) {
            System.out.println("没有首节点~~");
            return;
        }
        head = head.next;
    }
    // 删除索引位置
    public void remove(int index) {
        Node pre = findNode(index - 1);
        if (index == 0) {
            removeFirst();
            return;
        }
        if (pre == null) {
            System.out.println("索引异常~~~");
            return;
        }
        if (pre.next == null) {
            System.out.println("索引异常~~~");
            return;
        }
        pre.next = pre.next.next;
    }









    // 测试: (因为不会写测试类, 所以用main代替)
    public static void main(String[] args) {
        Test list = new Test();
        list.addFirst(1);
        list.addFirst(2);
        list.addFirst(3);
        list.addFirst(4);

        System.out.print("遍历1: ");
        list.loop1(System.out::print);
        System.out.println();

        System.out.print("遍历2: ");
        list.loop2(System.out::print);
        System.out.println();

        System.out.print("遍历3: ");
        for (Integer i : list) {
            System.out.print(i);
        }
        System.out.println();

        System.out.print("尾部增加节点: ");
        list.addLast(1);
        list.addLast(2);
        list.addLast(3);
        list.addLast(4);
        list.loop1(System.out::print);
        System.out.println();

        System.out.print("索引为3的值: ");
        System.out.println(list.get(3));

        System.out.print("往索引二插入节点8后的链表: ");
        list.insert(2,8);
        list.loop1(System.out::print);
        System.out.println();

        System.out.print("删除第一个节点(头节点): ");
        list.removeFirst();
        list.loop1(System.out::print);
        System.out.println();

        System.out.print("删除索引为3的元素: ");
        list.remove(3);
        list.loop1(System.out::print);
        System.out.println();
    }
}
